package com.rhyton.component.upload.dao.imp;

import java.io.File;
import java.io.IOException;
import java.util.Calendar;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;

import com.rhyton.component.upload.dao.UpDownloadFileDao;
import com.rhyton.component.upload.domain.AttactFile;

public class UpDownloadFileDaoImp implements UpDownloadFileDao, InitializingBean {

    /*
     * Windows下路径分隔符是"\" Unix与Linux下路径分隔符是"/"
     */
    private static Log log = LogFactory.getLog(UpDownloadFileDaoImp.class);

    private String rootDirectory;// 存放文件指定的文件夹绝对路径(在applicationContext-auth.xml中配置)

    public void afterPropertiesSet() throws Exception {
	if (!StringUtils.hasText(this.rootDirectory)) {
	    throw new IllegalArgumentException("Property 'rootDirectory' is required");
	}
    }

    public File getFile(AttactFile attactFile) throws DataAccessException {
	Assert.notNull(attactFile, "The attactFile must not be null");
	Assert.notNull(attactFile, "The storePath of attactFile must not be null");
	return new File(this.rootDirectory, attactFile.getStorePath());
    }

    public void deleteFile(AttactFile attactFile) throws DataAccessException {
	File file = this.getFile(attactFile);
	file.delete();
    }

    public void deleteByFileIds(List<AttactFile> attactFiles) throws DataAccessException {
	for (AttactFile attactFile : attactFiles) {
	    deleteFile(attactFile);
	}
    }

    public void upload(AttactFile af) throws DataAccessException {
	Assert.notNull(af, "The attactFile must not be null");
	Assert.notNull(af.getFile(), "The file of attactFile must not be null");
	try {
	    String storePath = addFile(af.getFile());
	    af.setStorePath(storePath); // set the store path
	} catch (IOException e) {
	    log.error(e.toString() + "向磁盘上载文件出错", e);
	    throw new DataAccessException(e.toString() + "向磁盘上载文件出错", e) {
		private static final long serialVersionUID = 1L;
	    };
	}// store in hard disk
    }

    /**
     * 保存附件并返回实际存放的路径
     * 
     * @param realFile
     *                真正要上传的文件
     * @return 文件存放的实际路径
     * @throws IOException
     */
    private String addFile(File realFile) throws IOException {
	File directory = dealDirectory(this.rootDirectory);
	String storeFileName = generateStoreFileName(realFile.getName());
	File file = new File(directory, storeFileName);
	FileCopyUtils.copy(realFile, file);
	return file.getAbsolutePath().substring(rootDirectory.length());
    }

    /**
     * 当subDirectoryName的目录不存在时,在<code>directory</code>下创建子目录<code>subDirectoryName</code>,并返回子目录.
     * 
     * @param directory
     * @param subDirectoryName
     *                子目录名称
     * @return
     */
    private static final File createSubDirectoryIfNotExist(File directory, String subDirectoryName) {
	File subdirectory = new File(directory, subDirectoryName);
	if (!subdirectory.exists()) {
	    subdirectory.mkdir();
	}
	return subdirectory;
    }

    private static final File createSubDirectoryIfNotExist(File directory, int subDirectoryName) {
	return createSubDirectoryIfNotExist(directory, Integer.toString(subDirectoryName));
    }

    /**
     * 创建附件存储的根目录，如果不存在时
     * 
     * @param rootDirectoryPath
     * @return 附件存储的根目录
     */
    private static final File createRootDirectoryIfNotExist(String rootDirectoryPath) {
	File rootDirectory = new File(rootDirectoryPath);
	try {
	    if (!rootDirectory.exists()) {
		rootDirectory.mkdir();
	    }
	} catch (Exception e) {
	    log.error("can not create StartPath directory File" + rootDirectoryPath, e);
	}
	return rootDirectory;
    }

    /**
     * 根据实现文件名产生存储时所用的文件名
     * 
     * @param realFileFullName
     *                实现文件名
     * @return 存储时所用的文件名
     */
    private String generateStoreFileName(String realFileFullName) {
	int i = realFileFullName.lastIndexOf(".");
	String extendName = (i != -1) ? realFileFullName.substring(i) : "";
	return (System.nanoTime()) + extendName;// 存入磁盘的文件名 id +"."+
    }

    /**
     * 根据当前时间产生附件存储的目录: rootDirectory/年/月/日/"纳秒.扩展名"
     * 
     * @param rootDirectoryPath
     *                存储附件的根目录
     * @return
     */
    private static final File dealDirectory(String rootDirectoryPath) {
	Calendar calendar = Calendar.getInstance();
	File rootDirectory = createRootDirectoryIfNotExist(rootDirectoryPath);
	File directory = createSubDirectoryIfNotExist(rootDirectory, calendar.get(Calendar.YEAR));
	directory = createSubDirectoryIfNotExist(directory, calendar.get(Calendar.MONTH));
	directory = createSubDirectoryIfNotExist(directory, calendar.get(Calendar.DATE));
	return directory;
    }

    //===================================The Setter/Getter Methods================================================//
    public String getRootDirectory() {
	return rootDirectory;
    }

    public void setRootDirectory(String startPath) {
	this.rootDirectory = startPath;
    }

}
